package jmine.selenium.services.errorlistener;

import jmine.tec.services.ServicesController;
import jmine.tec.services.api.Service;
import jmine.tec.services.api.ServiceAssertionFailedError;
import jmine.tec.services.api.ServiceExecutionException;
import jmine.tec.services.api.errorlistener.ServiceErrorListener;
import bancosys.tec.rtm.exception.RTMException;
import bancosys.tec.rtm.impl.exception.dao.ExceptionRecordDAO;
import bancosys.tec.rtm.impl.exception.domain.ExceptionRecord;

/**
 * {@link ServiceErrorListener} que busca no RTM algum registro referente ao erro ocorrido.
 * 
 * @author Rafael Volpato
 * @date Nov 18, 2009
 */
public class SeleniumServiceErrorListener implements ServiceErrorListener {

    private ServicesController servicesController;

    /**
     * @param servicesController the servicesController to set
     */
    public void setServicesController(ServicesController servicesController) {
        this.servicesController = servicesController;
    }

    /**
     * {@inheritDoc}
     */
    public void handleServiceError(Service<?> service, ServiceExecutionException exception) {
        this.addCauseFromRTM(service, exception);
    }

    /**
     * {@inheritDoc}
     */
    public void handleServiceFailure(Service<?> service, ServiceAssertionFailedError exception) {
        this.addCauseFromRTM(service, exception);
    }

    /**
     * {@inheritDoc}
     */
    public void handleServiceThrowable(Service<?> service, Throwable exception) {
        this.addCauseFromRTM(service, exception);
    }

    /**
     * Busca a ultima exception armazenada no RTM e adiciona como sendo a ULTIMA cause da exception.
     * 
     * @param service serviço
     * @param exception exception
     */
    private void addCauseFromRTM(Service<?> service, Throwable exception) {
        ExceptionRecordDAO dao = this.servicesController.getDAOFactory().getDAOByClass(ExceptionRecordDAO.class);
        try {
            ExceptionRecord exceptionRecord = dao.find(dao.findMaxId());
            Throwable t = exception;
            while (t.getCause() != null) {
                t = t.getCause();
            }
            if (t.getCause() == null) {
                t.initCause(new RTMRecordException(exceptionRecord));
            }
        } catch (RTMException e) {
            // Se nenhuma exception foi lançada no RTM, não tentar adicionar nenhuma causa.
        }
    }

    /**
     * Exception que encapsula um {@link ExceptionRecord}.
     * 
     * @author Rafael Volpato
     * @date Nov 18, 2009
     */
    private static final class RTMRecordException extends Exception {

        private ExceptionRecord exceptionRecord;

        /**
         * Construtor.
         * 
         * @param exceptionRecord exceptionRecord
         */
        public RTMRecordException(ExceptionRecord exceptionRecord) {
            this.exceptionRecord = exceptionRecord;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public String getMessage() {
            return this.exceptionRecord.getStack();
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public StackTraceElement[] getStackTrace() {
            return new StackTraceElement[0];
        }
    }
}
